Explore sexual size dimorphism in hummingbird species from Costa Rica
Evaluate Rensch’s Rule
You can have the sections listed here, for instance:
# read data
dat <- as.data.frame(read_excel("./data/raw/supplementary data.xlsx"))
# read tree
tree <- read.tree("./data/raw/imputed hummer tree 339 spp.tre")
dat$`scientific name`[dat$`scientific name` == "Phaetornis guy"] <- "Phaethornis guy"
dat$`scientific name`[dat$`scientific name` == "Phaetornis longirostris"] <- "Phaethornis longirostris"
dat$`scientific name`[dat$`scientific name` == "Heliomaster longisrostris"] <- "Heliomaster longirostris"
dat$scientific_name <- gsub(" ", "_", dat$`scientific name`)
tree$tip.label[tree$tip.label == "Amazilia_amabilis"] <- "Polyerata_amabilis"
tree$tip.label[tree$tip.label == "Hylocharis_eliciae"] <- "Chlorestes_eliciae"
tree$tip.label[tree$tip.label == "Chlorostilbon_canivetii"] <- "Cynanthus_canivetii"
tree$tip.label[tree$tip.label == "Elvira_cupreiceps"] <- "Microchera_cupreiceps"
tree$tip.label[tree$tip.label == "Calliphlox_bryantae"] <- "Philodice_bryantae"
tree$tip.label[tree$tip.label == "Amazilia_edward"] <- "Saucerottia_edward"
tree$tip.label[tree$tip.label == "Amazilia_saucerottei"] <- "Saucerottia_hoffmanni"
tree$tip.label[tree$tip.label == "Amazilia_saucerottei"] <- "Saucerottia_hoffmanni"
tree$tip.label[tree$tip.label == "Amazilia_candida"] <- "Chlorestes_candida"
tree$tip.label[tree$tip.label == "Elvira_chionura"] <- "Microchera_chonura"
# setdiff(unique(dat$scientific_name), tree$tip.label)
subtree <- drop.tip(phy = tree, tip = setdiff(tree$tip.label, unique(dat$scientific_name)))
names(dat) <- gsub(" ", ".", names(dat))
subtree2 <- subtree
subtree2$tip.label <- gsub("_", " ", subtree2$tip.label)
ggtree(subtree2, layout = "circular", col = viridis(10)[7]) + geom_tiplab(size = 4) +
theme(plot.margin = unit(c(30, 10, 30, 10), "mm"))(note that in the data supplied ln.SEX.weight variables are in natural log)
# model settings
v.cv.tree <- ape::vcv.phylo(subtree)
prior <- c(prior(normal(0, 10), "b"), prior(normal(0, 50), "Intercept"),
prior(student_t(3, 0, 20), "sd"), prior(student_t(3, 0, 20), "sigma"))
iter <- 10000male_x_mod <- brm(ln.female.weight ~ ln.male.weight + (1 | gr(scientific_name,
cov = v.cv.tree)), data = dat, family = gaussian(), data2 = list(v.cv.tree = v.cv.tree),
prior = prior, iter = iter, control = list(adapt_delta = 0.99,
max_treedepth = 15), file = "./data/processed/male_vs_female_size",
file_refit = "always")| priors | formula | iterations | chains | thinning | warmup | diverg_transitions | rhats > 1.05 | min_bulk_ESS | min_tail_ESS | seed | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | b-normal(0, 10) Intercept-normal(0, 50) sd-student_t(3, 0, 20) sigma-student_t(3, 0, 20) | ln.female.weight ~ ln.male.weight + (1 | gr(scientific_name, cov = v.cv.tree)) | 10000 | 4 | 1 | 5000 | 0 | 0 | 9817.964 | 11867.65 | 130978144 |
| Estimate | l-95% CI | u-95% CI | Rhat | Bulk_ESS | Tail_ESS | |
|---|---|---|---|---|---|---|
| b_Intercept | 0.197 | 0.085 | 0.313 | 1.001 | 9817.964 | 11867.65 |
| b_ln.male.weight | 0.838 | 0.780 | 0.897 | 1 | 14809.620 | 13099.05 |
log10_male_x_mod <- brm(lg10.female.weight ~ lg10.male.weight + (1 |
gr(scientific_name, cov = v.cv.tree)), data = dat, family = gaussian(),
data2 = list(v.cv.tree = v.cv.tree), prior = prior, iter = iter,
control = list(adapt_delta = 0.99, max_treedepth = 15), file = "./data/processed/log10_male_vs_female_size",
file_refit = "always")| priors | formula | iterations | chains | thinning | warmup | diverg_transitions | rhats > 1.05 | min_bulk_ESS | min_tail_ESS | seed | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | b-normal(0, 10) Intercept-normal(0, 50) sd-student_t(3, 0, 20) sigma-student_t(3, 0, 20) | lg10.female.weight ~ lg10.male.weight + (1 | gr(scientific_name, cov = v.cv.tree)) | 10000 | 4 | 1 | 5000 | 0 | 0 | 12310.95 | 12983.13 | 408928919 |
| Estimate | l-95% CI | u-95% CI | Rhat | Bulk_ESS | Tail_ESS | |
|---|---|---|---|---|---|---|
| b_Intercept | 0.086 | 0.038 | 0.137 | 1 | 12310.95 | 12983.13 |
| b_lg10.male.weight | 0.838 | 0.779 | 0.896 | 1 | 16789.93 | 14729.30 |
female_x_mod <- brm(ln.male.weight ~ ln.female.weight + (1 | gr(scientific_name,
cov = v.cv.tree)), data = dat, family = gaussian(), data2 = list(v.cv.tree = v.cv.tree),
prior = prior, iter = iter, control = list(adapt_delta = 0.99,
max_treedepth = 15), file = "./data/processed/female_vs_male_size",
file_refit = "always")| priors | formula | iterations | chains | thinning | warmup | diverg_transitions | rhats > 1.05 | min_bulk_ESS | min_tail_ESS | seed | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | b-normal(0, 10) Intercept-normal(0, 50) sd-student_t(3, 0, 20) sigma-student_t(3, 0, 20) | ln.male.weight ~ ln.female.weight + (1 | gr(scientific_name, cov = v.cv.tree)) | 10000 | 4 | 1 | 5000 | 0 | 0 | 12599.43 | 12003.39 | 1212623959 |
| Estimate | l-95% CI | u-95% CI | Rhat | Bulk_ESS | Tail_ESS | |
|---|---|---|---|---|---|---|
| b_Intercept | -0.147 | -0.288 | -0.006 | 1 | 12599.43 | 12003.39 |
| b_ln.female.weight | 1.139 | 1.061 | 1.215 | 1 | 15499.92 | 14691.24 |
log10_female_x_mod <- brm(lg10.male.weight ~ lg10.female.weight +
(1 | gr(scientific_name, cov = v.cv.tree)), data = dat, family = gaussian(),
data2 = list(v.cv.tree = v.cv.tree), prior = prior, iter = iter,
control = list(adapt_delta = 0.99, max_treedepth = 15), file = "./data/processed/log10_female_vs_male_size",
file_refit = "always")| priors | formula | iterations | chains | thinning | warmup | diverg_transitions | rhats > 1.05 | min_bulk_ESS | min_tail_ESS | seed | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | b-normal(0, 10) Intercept-normal(0, 50) sd-student_t(3, 0, 20) sigma-student_t(3, 0, 20) | lg10.male.weight ~ lg10.female.weight + (1 | gr(scientific_name, cov = v.cv.tree)) | 10000 | 4 | 1 | 5000 | 0 | 0 | 16768.06 | 15102.63 | 769877839 |
| Estimate | l-95% CI | u-95% CI | Rhat | Bulk_ESS | Tail_ESS | |
|---|---|---|---|---|---|---|
| b_Intercept | -0.064 | -0.127 | -0.002 | 1 | 16768.06 | 15511.65 |
| b_lg10.female.weight | 1.139 | 1.061 | 1.217 | 1 | 20912.58 | 15102.63 |
male_vs_ssd_mod <- brm(aboluteSSD ~ ln.male.weight + (1 | gr(scientific_name,
cov = v.cv.tree)), data = dat, family = gaussian(), data2 = list(v.cv.tree = v.cv.tree),
prior = prior, iter = iter, control = list(adapt_delta = 0.99,
max_treedepth = 15), file = "./data/processed/male_vs_abs_SSD",
file_refit = "always")| priors | formula | iterations | chains | thinning | warmup | diverg_transitions | rhats > 1.05 | min_bulk_ESS | min_tail_ESS | seed | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | b-normal(0, 10) Intercept-normal(0, 50) sd-student_t(3, 0, 20) sigma-student_t(3, 0, 20) | aboluteSSD ~ ln.male.weight + (1 | gr(scientific_name, cov = v.cv.tree)) | 10000 | 4 | 1 | 5000 | 0 | 0 | 18468.74 | 14046.47 | 920571681 |
| Estimate | l-95% CI | u-95% CI | Rhat | Bulk_ESS | Tail_ESS | |
|---|---|---|---|---|---|---|
| b_Intercept | 0.011 | -0.099 | 0.116 | 1 | 18468.74 | 14046.47 |
| b_ln.male.weight | 0.065 | 0.006 | 0.123 | 1.001 | 25029.29 | 15934.31 |
log10_male_vs_ssd_mod <- brm(aboluteSSD ~ lg10.male.weight + (1 |
gr(scientific_name, cov = v.cv.tree)), data = dat, family = gaussian(),
data2 = list(v.cv.tree = v.cv.tree), prior = prior, iter = iter,
control = list(adapt_delta = 0.99, max_treedepth = 15), file = "./data/processed/log10_male_vs_abs_SSD",
file_refit = "always")| priors | formula | iterations | chains | thinning | warmup | diverg_transitions | rhats > 1.05 | min_bulk_ESS | min_tail_ESS | seed | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | b-normal(0, 10) Intercept-normal(0, 50) sd-student_t(3, 0, 20) sigma-student_t(3, 0, 20) | aboluteSSD ~ lg10.male.weight + (1 | gr(scientific_name, cov = v.cv.tree)) | 10000 | 4 | 1 | 5000 | 0 | 0 | 14877.92 | 11685.19 | 416614627 |
| Estimate | l-95% CI | u-95% CI | Rhat | Bulk_ESS | Tail_ESS | |
|---|---|---|---|---|---|---|
| b_Intercept | 0.011 | -0.101 | 0.113 | 1.001 | 14877.92 | 11685.19 |
| b_lg10.male.weight | 0.150 | 0.019 | 0.286 | 1.001 | 20376.34 | 14563.92 |
female_vs_ssd_mod <- brm(aboluteSSD ~ ln.female.weight + (1 | gr(scientific_name,
cov = v.cv.tree)), data = dat, family = gaussian(), data2 = list(v.cv.tree = v.cv.tree),
prior = prior, iter = iter, control = list(adapt_delta = 0.99,
max_treedepth = 15), file = "./data/processed/female_vs_abs_SSD.rds",
file_refit = "always")| priors | formula | iterations | chains | thinning | warmup | diverg_transitions | rhats > 1.05 | min_bulk_ESS | min_tail_ESS | seed | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | b-normal(0, 10) Intercept-normal(0, 50) sd-student_t(3, 0, 20) sigma-student_t(3, 0, 20) | aboluteSSD ~ ln.female.weight + (1 | gr(scientific_name, cov = v.cv.tree)) | 10000 | 4 | 1 | 5000 | 0 | 0 | 19482.34 | 14833.66 | 65846261 |
| Estimate | l-95% CI | u-95% CI | Rhat | Bulk_ESS | Tail_ESS | |
|---|---|---|---|---|---|---|
| b_Intercept | 0.053 | -0.065 | 0.167 | 1 | 19482.34 | 14833.66 |
| b_ln.female.weight | 0.042 | -0.027 | 0.111 | 1 | 25007.44 | 15677.30 |
log10_female_vs_ssd_mod <- brm(aboluteSSD ~ lg10.female.weight + (1 |
gr(scientific_name, cov = v.cv.tree)), data = dat, family = gaussian(),
data2 = list(v.cv.tree = v.cv.tree), prior = prior, iter = iter,
control = list(adapt_delta = 0.99, max_treedepth = 15), file = "./data/processed/log10_female_vs_abs_SSD",
file_refit = "always")| priors | formula | iterations | chains | thinning | warmup | diverg_transitions | rhats > 1.05 | min_bulk_ESS | min_tail_ESS | seed | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | b-normal(0, 10) Intercept-normal(0, 50) sd-student_t(3, 0, 20) sigma-student_t(3, 0, 20) | aboluteSSD ~ lg10.female.weight + (1 | gr(scientific_name, cov = v.cv.tree)) | 10000 | 4 | 1 | 5000 | 0 | 0 | 15257.46 | 13088.31 | 1833450209 |
| Estimate | l-95% CI | u-95% CI | Rhat | Bulk_ESS | Tail_ESS | |
|---|---|---|---|---|---|---|
| b_Intercept | 0.052 | -0.070 | 0.168 | 1 | 15257.46 | 13088.31 |
| b_lg10.female.weight | 0.098 | -0.062 | 0.258 | 1 | 20374.40 | 15549.23 |
fit <- readRDS("./data/processed/log10_male_vs_female_size.rds")
gg_fit <- conditional_effects(fit)
pred_dat <- gg_fit$lg10.male.weight
fit_summ <- draw_summary(posterior::as_draws_array(fit), variables = c("b_Intercept",
"b_lg10.male.weight"), robust = TRUE, probs = c(0.025, 0.975))
ggplot(data = dat, mapping = aes(x = lg10.male.weight, y = lg10.female.weight)) +
geom_segment(data = pred_dat, mapping = aes(x = min(pred_dat$lg10.male.weight),
y = min(pred_dat$estimate__), xend = max(pred_dat$lg10.male.weight),
yend = max(pred_dat$estimate__))) + geom_ribbon(data = pred_dat,
aes(ymin = lower__, ymax = upper__), fill = "gray", alpha = 0.3) +
geom_point(color = viridis(10, alpha = 0.6)[7], size = 3) + theme_classic(base_size = 20) +
labs(x = "log10(male body mass)", y = "log10(female body mass)")fit <- readRDS("./data/processed/log10_male_vs_abs_SSD.rds")
gg_fit <- conditional_effects(fit)
pred_dat <- gg_fit$lg10.male.weight
fit_summ <- draw_summary(posterior::as_draws_array(fit), variables = c("b_Intercept",
"b_lg10.male.weight"), robust = TRUE, probs = c(0.025, 0.975))
ggplot(data = dat, mapping = aes(x = lg10.male.weight, y = aboluteSSD)) +
geom_segment(data = pred_dat, mapping = aes(x = min(pred_dat$lg10.male.weight),
y = min(pred_dat$estimate__), xend = max(pred_dat$lg10.male.weight),
yend = max(pred_dat$estimate__))) + geom_ribbon(data = pred_dat,
aes(ymin = lower__, ymax = upper__), fill = "gray", alpha = 0.3) +
geom_point(color = viridis(10, alpha = 0.6)[7], size = 3) + theme_classic(base_size = 20) +
labs(x = "log10(male body mass)", y = "Dimorphism (absolute SSD)")fit <- readRDS("./data/processed/log10_female_vs_abs_SSD.rds")
gg_fit <- conditional_effects(fit)
pred_dat <- gg_fit$lg10.female.weight
fit_summ <- draw_summary(posterior::as_draws_array(fit), variables = c("b_Intercept",
"b_lg10.female.weight"), robust = TRUE, probs = c(0.025, 0.975))
ggplot(data = dat, mapping = aes(x = lg10.female.weight, y = aboluteSSD)) +
# geom_segment(data = pred_dat, mapping = aes(x =
# min(pred_dat$lg10.female.weight), y =
# min(pred_dat$estimate__), xend =
# max(pred_dat$lg10.female.weight), yend =
# max(pred_dat$estimate__))) + geom_ribbon(data = pred_dat,
# aes(ymin = lower__, ymax = upper__), fill = 'gray', alpha
# = 0.3) +
geom_point(color = viridis(10, alpha = 0.6)[7], size = 3) + theme_classic(base_size = 20) +
labs(x = "log10(female body mass)", y = "Dimorphism (absolute SSD)")| priors | formula | iterations | chains | thinning | warmup | diverg_transitions | rhats > 1.05 | min_bulk_ESS | min_tail_ESS | seed | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | b-normal(0, 10) Intercept-normal(0, 50) sd-student_t(3, 0, 20) sigma-student_t(3, 0, 20) | aboluteSSD ~ ln.female.weight + (1 | gr(scientific_name, cov = v.cv.tree)) | 10000 | 4 | 1 | 5000 | 0 | 0 | 5290.322 | 8379.279 | 65846261 |
| 2 | b-normal(0, 10) Intercept-normal(0, 50) sd-student_t(3, 0, 20) sigma-student_t(3, 0, 20) | ln.male.weight ~ ln.female.weight + (1 | gr(scientific_name, cov = v.cv.tree)) | 10000 | 4 | 1 | 5000 | 0 | 0 | 3120.988 | 4220.375 | 1212623959 |
| 3 | b-normal(0, 10) Intercept-normal(0, 50) sd-student_t(3, 0, 20) sigma-student_t(3, 0, 20) | aboluteSSD ~ lg10.female.weight + (1 | gr(scientific_name, cov = v.cv.tree)) | 10000 | 4 | 1 | 5000 | 0 | 0 | 4821.640 | 7222.290 | 1833450209 |
| 4 | b-normal(0, 10) Intercept-normal(0, 50) sd-student_t(3, 0, 20) sigma-student_t(3, 0, 20) | lg10.male.weight ~ lg10.female.weight + (1 | gr(scientific_name, cov = v.cv.tree)) | 10000 | 4 | 1 | 5000 | 0 | 0 | 2910.664 | 4534.518 | 769877839 |
| 5 | b-normal(0, 10) Intercept-normal(0, 50) sd-student_t(3, 0, 20) sigma-student_t(3, 0, 20) | aboluteSSD ~ lg10.male.weight + (1 | gr(scientific_name, cov = v.cv.tree)) | 10000 | 4 | 1 | 5000 | 0 | 0 | 4105.747 | 7263.945 | 416614627 |
| 6 | b-normal(0, 10) Intercept-normal(0, 50) sd-student_t(3, 0, 20) sigma-student_t(3, 0, 20) | lg10.female.weight ~ lg10.male.weight + (1 | gr(scientific_name, cov = v.cv.tree)) | 10000 | 4 | 1 | 5000 | 0 | 0 | 2882.190 | 4256.579 | 408928919 |
| 7 | b-normal(0, 10) Intercept-normal(0, 50) sd-student_t(3, 0, 20) sigma-student_t(3, 0, 20) | aboluteSSD ~ ln.male.weight + (1 | gr(scientific_name, cov = v.cv.tree)) | 10000 | 4 | 1 | 5000 | 0 | 0 | 4453.437 | 8040.974 | 920571681 |
| 8 | b-normal(0, 10) Intercept-normal(0, 50) sd-student_t(3, 0, 20) sigma-student_t(3, 0, 20) | ln.female.weight ~ ln.male.weight + (1 | gr(scientific_name, cov = v.cv.tree)) | 10000 | 4 | 1 | 5000 | 0 | 0 | 2777.937 | 3908.529 | 130978144 |
Session information
## R version 4.2.2 Patched (2022-11-10 r83330)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 20.04.5 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0
##
## locale:
## [1] LC_CTYPE=es_ES.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=es_CR.UTF-8 LC_COLLATE=es_ES.UTF-8
## [5] LC_MONETARY=es_CR.UTF-8 LC_MESSAGES=es_ES.UTF-8
## [7] LC_PAPER=es_CR.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=es_CR.UTF-8 LC_IDENTIFICATION=C
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] ggplot2_3.4.0 viridis_0.6.2 viridisLite_0.4.1
## [4] brms_2.18.0 Rcpp_1.0.10 sketchy_1.0.2
## [7] brmsish_1.0.0 ggtree_3.6.2 readxl_1.4.1
## [10] ape_5.6-2 xaringanExtra_0.7.0 rprojroot_2.0.3
## [13] formatR_1.12 knitr_1.41 kableExtra_1.3.4
##
## loaded via a namespace (and not attached):
## [1] colorspace_2.1-0 ellipsis_0.3.2 ggridges_0.5.4
## [4] markdown_1.3 base64enc_0.1-3 aplot_0.1.9
## [7] rstudioapi_0.14 farver_2.1.1 rstan_2.21.7
## [10] remotes_2.4.2 DT_0.26 fansi_1.0.4
## [13] mvtnorm_1.1-3 xml2_1.3.3 codetools_0.2-19
## [16] bridgesampling_1.1-2 cachem_1.0.6 shinythemes_1.2.0
## [19] bayesplot_1.9.0 jsonlite_1.8.4 packrat_0.8.1
## [22] ggdist_3.2.1 shiny_1.7.3 compiler_4.2.2
## [25] httr_1.4.4 backports_1.4.1 Matrix_1.5-1
## [28] fastmap_1.1.0 lazyeval_0.2.2 cli_3.6.0
## [31] later_1.3.0 prettyunits_1.1.1 htmltools_0.5.4
## [34] tools_4.2.2 igraph_1.3.5 coda_0.19-4
## [37] gtable_0.3.1 glue_1.6.2 reshape2_1.4.4
## [40] dplyr_1.0.10 posterior_1.3.1 cellranger_1.1.0
## [43] jquerylib_0.1.4 vctrs_0.5.2 svglite_2.1.0
## [46] nlme_3.1-162 crosstalk_1.2.0 tensorA_0.36.2
## [49] xfun_0.35 stringr_1.5.0 ps_1.7.2
## [52] rvest_1.0.3 mime_0.12 miniUI_0.1.1.1
## [55] lifecycle_1.0.3 gtools_3.9.3 zoo_1.8-11
## [58] scales_1.2.1 colourpicker_1.2.0 promises_1.2.0.1
## [61] Brobdingnag_1.2-9 parallel_4.2.2 inline_0.3.19
## [64] shinystan_2.6.0 yaml_2.3.6 pbapply_1.6-0
## [67] gridExtra_2.3 ggfun_0.0.9 StanHeaders_2.21.0-7
## [70] loo_2.5.1 yulab.utils_0.0.6 sass_0.4.4
## [73] stringi_1.7.12 highr_0.9 dygraphs_1.1.1.6
## [76] tidytree_0.4.2 checkmate_2.1.0 pkgbuild_1.3.1
## [79] rlang_1.0.6 pkgconfig_2.0.3 systemfonts_1.0.4
## [82] matrixStats_0.62.0 distributional_0.3.1 evaluate_0.19
## [85] lattice_0.20-45 purrr_1.0.1 labeling_0.4.2
## [88] treeio_1.23.0 rstantools_2.2.0 patchwork_1.1.2
## [91] htmlwidgets_1.5.4 cowplot_1.1.1 processx_3.8.0
## [94] tidyselect_1.2.0 plyr_1.8.7 magrittr_2.0.3
## [97] R6_2.5.1 generics_0.1.3 withr_2.5.0
## [100] pillar_1.8.1 xts_0.12.2 abind_1.4-5
## [103] tibble_3.1.8 crayon_1.5.2 uuid_1.1-0
## [106] utf8_1.2.2 rmarkdown_2.19 grid_4.2.2
## [109] callr_3.7.3 threejs_0.3.3 digest_0.6.31
## [112] webshot_0.5.4 xtable_1.8-4 tidyr_1.3.0
## [115] httpuv_1.6.6 gridGraphics_0.5-1 RcppParallel_5.1.5
## [118] stats4_4.2.2 munsell_0.5.0 ggplotify_0.1.0
## [121] bslib_0.4.2 shinyjs_2.1.0